///************************************************************************
/// <copyrigth>2018-2019 Corporation.All Rights Reserved</copyrigth>
/// <author>tangyingzhong</author>
/// <contact>tangyz114987@outlook.com</contact>
/// <version>v1.0.0</version>
/// <describe>
/// Decode video with hardware
///</describe>
/// <date>2021/6/26</date>
///***********************************************************************
#ifndef VIDEOHARDDECODER_H
#define VIDEOHARDDECODER_H

#include "IVideoD3dRender.h"
#include "IVideoHardDecoder.h"

#define HARD_DEVICE_TYPE_NAME "dxva2"

class VideoHardDecoder :public IVideoHardDecoder
{
public:
	typedef IVideoD3dRender* VideoRender;

public:
	// Construct the VideoHardDecoder
	VideoHardDecoder();

	// Detructe the VideoHardDecoder
	virtual ~VideoHardDecoder();

private:
	// Forbid the copy VideoHardDecoder
	VideoHardDecoder(const VideoHardDecoder& other) {	};

	// Forbid the assigment of VideoHardDecoder
	VideoHardDecoder& operator=(const VideoHardDecoder& other) { return *this; };

public:
	// Init the decoder
	virtual bool Init(VideoTypeEnum eVideoType, void* pWindowHandle);

	// Excute the decoding
	virtual bool Excute(uint8_t* pSrcData,
		int iSrcSize,
		uint8_t* pDst,
		int& iDstSize,
		int& iFrameWidth,
		int& iFrameHeight);

	// Flush the decode to ensure all the frame output
	virtual void Flush();

	// Is current system support hard decoder
	virtual bool IsSupportHardDecode(VideoTypeEnum eVideoType);

private:
	// Initialize the decoder
	void Initialize();

	// Destory the decoder
	void Destory();

	// Create video render
	void CreateRender();

	// Destory video render
	void DestoryRender();

	// Init the video render
	bool InitVideoRender();

	// Init the hard device
	bool InitHardDevice(AVCodecContext* pAvctx, AVCodec* pDecoder);

	// Release the decoder
	void ReleaseDecoder();

	// Decode package
	bool DecodePacket(AVCodecContext* pAvctx, 
		AVPacket* pPacket, 
		uint8_t* pDst, 
		int& iDstSize);

	// Is show data by the GPU directly
	bool IsShowByGpu();

	// Render the data by GPU
	bool RenderByGpu(AVFrame* pFrame);

private:
	// Get the D3dRender
	inline VideoRender GetVideoRender() const
	{
		return m_pVideoRender;
	}

	// Set the D3dRender
	inline void SetVideoRender(VideoRender pVideoRender)
	{
		m_pVideoRender = pVideoRender;
	}

	// Get the WinHandle
	inline void* GetWinHandle() const
	{
		return m_pWinHandle;
	}

	// Set the WinHandle
	inline void SetWinHandle(void* pWinHandle)
	{
		m_pWinHandle = pWinHandle;
	}

	// Get the DecCodecCtx
	inline AVCodecContext* GetDecCodecCtx() const
	{
		return m_pDecCodecCtx;
	}

	// Set the DecCodecCtx
	inline void SetDecCodecCtx(AVCodecContext* pDecCodecCtx)
	{
		m_pDecCodecCtx = pDecCodecCtx;
	}

	// Get the PixFmt
	inline AVPixelFormat GetPixFmt() const
	{
		return m_ehwPixFmt;
	}

	// Set the PixFmt
	inline void SetPixFmt(AVPixelFormat ehwPixFmt)
	{
		m_ehwPixFmt = ehwPixFmt;
	}

	// Get the PhwDevCtx
	inline AVBufferRef* GethwDevCtx() const
	{
		return m_phwDevCtx;
	}

	// Set the PhwDevCtx
	inline void SethwDevCtx(AVBufferRef* phwDevCtx)
	{
		m_phwDevCtx = phwDevCtx;
	}

	// Get the IsHaveInitDecoder
	inline bool GetIsHaveInitDecoder() const
	{
		return m_bIsHaveInitDecoder;
	}

	// Set the IsHaveInitDecoder
	inline void SetIsHaveInitDecoder(bool bIsHaveInitDecoder)
	{
		m_bIsHaveInitDecoder = bIsHaveInitDecoder;
	}

	// Get the disposed status
	inline bool GetDisposed() const
	{
		return m_bDisposed;
	}

	// Set the disposed status
	inline void SetDisposed(bool bDisposed)
	{
		m_bDisposed = bDisposed;
	}

private:
	// Video render
	VideoRender m_pVideoRender;
	
	// Window handle
	void* m_pWinHandle;
	
	// Decode context
	AVCodecContext* m_pDecCodecCtx;

	// Image's pixel format
	AVPixelFormat m_ehwPixFmt;
	
	// Hardware decoder context
	AVBufferRef* m_phwDevCtx;
	
	// Is init the decoder
	bool m_bIsHaveInitDecoder;
	
	// Disposed status
	bool m_bDisposed;
};

#endif // VIDEOHARDDECODER_H
